package hotel.quartz.oversea.job.switchs;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import hotel.base.oversea.constant.ApiConstans;
import hotel.base.oversea.constant.CommonConstants;
import hotel.base.oversea.constant.CommonUrlConstants;
import hotel.base.oversea.constant.SwitchConstants;
import hotel.base.oversea.constant.quartz.UrlSwitchsEnums;
import hotel.base.oversea.utils.Result;
import hotel.quartz.oversea.config.service.RedisService;
import hotel.quartz.oversea.entity.form.JobForm;
import hotel.quartz.oversea.job.base.BaseJob;
import hotel.quartz.oversea.service.JobAndTriggerService;
import hotel.quartz.oversea.vo.switchs.SwitchMasterHotelVo;
import hotel.quartz.oversea.util.JobRestTemplateUtils;
import hotel.quartz.oversea.vo.switchs.DltHotelEntityVo;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.JobExecutionContext;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * <p>
 *  Switchs Hotel Sub Job
 * </p>
 *
 * @description: Switchs Hotel Sub Job
 * @author: qiuyy
 * @date: 2020-05-26 13:22
 * @version: V1.0
 */
@Slf4j
public class SwitchHotelSubJob implements BaseJob {
    private String jobGroupName = SwitchConstants.JOB_GROUP_NAME_SWITCHS;
    private String jobClassName = this.getClass().getName();
    private String redisSwChildIdsPageIndex = SwitchConstants.REDIS_SWITCH_HOTEL_CHILD_IDS_PAGE_INDEX;
    private  int pageSize = ApiConstans.SW_PAGE_SIZE;
    private String timestamp = "Shsj"+String.valueOf(System.currentTimeMillis());
    private int thisRedisCount = SwitchConstants.REDIS_SW_HOTEL_CHILD_INFOS_WAIT_COUNT;
    private String redisWaitSaveKey = SwitchConstants.REDIS_SW_HOTEL_CHILD_INFOS_WAIT_SAVE;


    @Autowired
    private JobAndTriggerService jobAndTriggerService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedisService redisService;
    @Autowired
    private RestTemplate restTemplate;
    /**
     * 该接口 待定
     *
     * 子酒店数据
     * 上游接口中：缓存子酒店信息集map（hotelId，masterHotelId）--> SwitchConstants.SWITCH_HOTEL_CHILD_IDS
     *
     * 结果：获取所有子酒店， 指定第三方参数pageIndex页码>0 ，不指定酒店。页码返回数据可能为空，表示已无数据无下一页
     *
     * @param jobExecutionContext
     */
    @Override
    @SneakyThrows
    public void execute(JobExecutionContext jobExecutionContext) {
        log.info("Switchs Hotel Sub Job {} >>>>>>>> 携程子酒店信息获取执行时间: {}", timestamp, DateUtil.now());
        String accessToken = "";
      /*  String host = CommonUrlConstants.SWITCHS_HOST;*/
        String host= CommonUrlConstants.SWITCHS_ONLINE_HOST;
        String childHotelUrl = host + UrlSwitchsEnums.subHotel.GET.getValue();// + "?access_token="+accessToken;
        String saveHotelUrl = host + UrlSwitchsEnums.subHotel.SAVE.getValue();// + "?access_token="+accessToken;
        boolean check = checkSaveRedisData(saveHotelUrl);
        if(!check){
            //当前需查询的城市的酒店第三方接口页码pageIndex
            String pageIndex = getChildHotelPageIndex();
            Map<String,Object> params = new HashMap();
            params.put("masterHotelID",0);
            params.put("hotelID",0);
            params.put("pageIndex",Integer.valueOf(pageIndex));
            params.put("pageSize",pageSize);
            requestChildHotelDataPage(JSON.toJSONString(params),pageIndex,childHotelUrl,saveHotelUrl,accessToken);
        }

        log.info("Switchs Hotel Sub Job {} >>>>>>>> 携程子酒店信息获取结束时间: {}",timestamp, DateUtil.now());
    }

    /**
     * 校验是否需要保存缓存的数据
     * @param saveUrl
     * @return
     */
    private boolean checkSaveRedisData(String saveUrl) {
        log.info("Switchs Hotel Sub Job {} 携程子酒店信息定时器进入方法 checkSaveRedisData",timestamp);
        Map<String,List<DltHotelEntityVo>> getInfos = getRedisWaitData();
        if(null != getInfos && getInfos.size()>=thisRedisCount){
            //缓存酒店数据达到大于等于thisRedisCount，则执行保存到数据库操作，可能大于thisRedisCount比如数据操作保存失败还原加入到redis
            boolean result = requestSaveWaitDataApi(saveUrl,getInfos);
            if(result){
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }
    /**
     * 调用保存缓存数据集合接口
     * @param saveUrl
     * @param redisWaitDataSaveMap
     * @return
     */
    private boolean requestSaveWaitDataApi(String saveUrl,Map<String,List<DltHotelEntityVo>> redisWaitDataSaveMap) {
        if(null == redisWaitDataSaveMap || redisWaitDataSaveMap.size()==0){
            log.warn("Switchs Hotel Sub Job {} 携程子酒店信息进入方法 requestSaveWaitDataApi 待保存数据redisWaitDataSaveMap为空",timestamp);
            return true;
        }
        log.info("Switchs Hotel Sub Job {} 携程子酒店信息进入方法 requestSaveWaitDataApi",timestamp);
        Map map = new HashMap();
        map.put("switchHotelInfoVosMap",redisWaitDataSaveMap);
        //调用前,删除当前缓存的酒店数据，让下一次定时器正常查询上游接口。若调用结果失败则还原加入缓存
        deleteRedisWaitSaveData();
        //发起请求
        Result response = JobRestTemplateUtils.post(saveUrl, JSON.toJSONString(map),restTemplate);
        if(response.getCode()== CommonConstants.SUCCESS){
            log.info("Switchs Hotel Sub Job {} requestSaveWaitDataApi 保存数据成功",timestamp);
            return true;
        }else{
            log.error("Switchs Hotel Sub Job {} requestSaveWaitDataApi 异常错误: {}",timestamp,response);
            backPutRedisWaitSaveData(redisWaitDataSaveMap);
            return false;
        }
    }
    /**
     * 删除缓存的待保存数据
     * @return
     */
    public void deleteRedisWaitSaveData(){
        log.info("Switchs Hotel Sub Job {} 携程子酒店信息进入方法 deleteRedisWaitSaveData 删除当前携程子酒店信息定时器数据缓存",timestamp);
        redisTemplate.delete(redisWaitSaveKey);
    }
    /**
     * 还原追加回去待保存数据
     * @return
     */
    public void backPutRedisWaitSaveData(Map<String,List<DltHotelEntityVo>> redisWaitDataMap){
        log.info("Switchs Hotel Sub Job {} 携程子酒店信息进入方法 backPutRedisWaitSaveData 还原追加当前酒店信息缓存 ",timestamp);
        //还原redis数据
        Map<String,List<DltHotelEntityVo>> getRedisMap = (Map<String,List<DltHotelEntityVo>>)redisService.get(redisWaitSaveKey);
        if(null != getRedisMap && getRedisMap.size()>0){
            getRedisMap.putAll(redisWaitDataMap);
        }else{
            getRedisMap = redisWaitDataMap;
        }
        redisService.set(redisWaitSaveKey,getRedisMap);
    }

    /**
     * 获取保存在缓存中的待save的数据
     */
    private Map<String,List<DltHotelEntityVo>> getRedisWaitData() {
        return (Map<String,List<DltHotelEntityVo>>)redisService.get(redisWaitSaveKey);
    }

    /**
     * 查询指定城市的某些酒店列表数据：根据子酒店，页码index定位
     */
    public void requestChildHotelDataPage(String paramsJson,String pageIndex,String cityHotelUrl,String saveUrl,String accessToken){
        log.info("Switchs Hotel Sub Job {} 携程子酒店信息进入方法 requestChildHotelDataPage: {},{}",timestamp,paramsJson,accessToken);
        //发起请求
        Result response = JobRestTemplateUtils.post(cityHotelUrl,paramsJson,restTemplate);
        if(response.getCode()== CommonConstants.SUCCESS){
            if(null!= response.getData() && null != JSON.parseObject(JSON.toJSONString(response.getData())).getString("dltHotelEntityList")){
                //解析响应结果
                String datajson = JSON.toJSONString(response.getData());
                String hotelStr = JSON.parseObject(datajson).getString("dltHotelEntityList");
                List<SwitchMasterHotelVo> hotelData = (List<SwitchMasterHotelVo>) JSON.parseObject(hotelStr,List.class);
                if(null == hotelData || hotelData.size()==0){
                    //当前页面pageIndex查询结果无数据
                    //无数据也没下一页，redis数据操作保存，保存成功后暂停定时器
                    successUpdateSaveEnding(saveUrl);
                }else{
                    //查询到数据，存入redis
                    Map dataMap = new HashMap();
                    dataMap.put(UUID.randomUUID().toString(),hotelData);
                    boolean setResultRedis = savePutRedisWaitData(dataMap);
                    if(setResultRedis){
                        //只要有数据就定义为还有下一页，更新redis城市index
                        int newIndex = Integer.valueOf(pageIndex)+1;
                        setChildHotelPageIndex(String.valueOf(newIndex));
                    }else{
                        //更新失败，不更新标识，下一次定时器继续查询当前
                        log.error("Switchs Hotel Sub Job {} 携程子酒店信息定时器 setResultRedis 异常错误: {},{}",timestamp,response,paramsJson);
                    }
                }
            }else{
                //当前页面pageIndex查询结果无数据
                //无数据也没下一页，redis数据操作保存，保存成功后暂停定时器
                successUpdateSaveEnding(saveUrl);
            }
        }else{
            //异常错误，redis子酒店无变化，定时器下次进入继续查询当前酒店
            //endingJob(false);
            log.error("Switchs Hotel Sub Job {} 获取携程子酒店信息 返回失败: {},{}",timestamp,response,paramsJson);
        }
    }
    /**
     * 成功请求酒店房型接口后，合法酒店房型数据，追加进缓存中
     */
    private boolean savePutRedisWaitData(Map<String, List<Long>> mapRealRoomVoMap) {
        Map<String,List<Long>> getRedisMap = (Map<String,List<Long>>)redisService.get(redisWaitSaveKey);
        if(null != getRedisMap && getRedisMap.size()>0){
            getRedisMap.putAll(mapRealRoomVoMap);
        }else{
            getRedisMap = mapRealRoomVoMap;
        }
        boolean result = redisService.set(redisWaitSaveKey,getRedisMap);
        return result;
    }
    /**
     * 最后一页 更新掉剩余缓存待保存的数据，结束定时器
     */
    public void successUpdateSaveEnding(String saveUrl){
        boolean re = requestSaveWaitDataApi(saveUrl,getRedisWaitData());
        if(re){
            //已最后一页，暂停定时器,删除rediskey
            JobForm jobForm = new JobForm();
            jobForm.setJobClassName(jobClassName);
            jobForm.setJobGroupName(jobGroupName);
            try {
                jobAndTriggerService.pauseJob(jobForm);
                 deleteRedisChildHotelIndex();
                log.warn("Switchs Hotel Sub Job {} 携程子酒店定时器执行暂停！: {},{}",timestamp,jobGroupName,jobClassName);
            } catch (SchedulerException e) {
                log.error(e.getMessage(),e);
            }
        }else{
            log.error("Switchs Hotel Sub Job {} 最后一页保存操作 异常错误: {},{}",timestamp);
        }
    }

    public String getChildHotelPageIndex(){
        String index = (String)redisTemplate.opsForValue().get(redisSwChildIdsPageIndex);
        if(null == index){
            index  = "1";//接口参数要求  大于0
        }
        return index;
    }
    public void setChildHotelPageIndex(String newIndex){
        redisTemplate.opsForValue().set(redisSwChildIdsPageIndex,newIndex);
    }
    public void deleteRedisChildHotelIndex(){
        redisTemplate.delete(redisSwChildIdsPageIndex);
    }


}
